#pragma once

#include "../server.hpp"
#include <fstream>
#include <sys/stat.h>
#include <regex>
#define DEFAULT_TIMEOUT 30

std::unordered_map<int, std::string> statu_msg_ =
            {
                {100, "Continue"},
                {101, "Switching Protocol"},
                {102, "Processing"},
                {103, "Early Hints"},
                {200, "OK"},
                {201, "Created"},
                {202, "Accepted"},
                {203, "Non-Authoritative Information"},
                {204, "No Content"},
                {205, "Reset Content"},
                {206, "Partial Content"},
                {207, "Multi-Status"},
                {208, "Already Reported"},
                {226, "IM Used"},
                {300, "Multiple Choice"},
                {301, "Moved Permanently"},
                {302, "Found"},
                {303, "See Other"},
                {304, "Not Modified"},
                {305, "Use Proxy"},
                {306, "unused"},
                {307, "Temporary Redirect"},
                {308, "Permanent Redirect"},
                {400, "Bad Request"},
                {401, "Unauthorized"},
                {402, "Payment Required"},
                {403, "Forbidden"},
                {404, "Not Found"},
                {405, "Method Not Allowed"},
                {406, "Not Acceptable"},
                {407, "Proxy Authentication Required"},
                {408, "Request Timeout"},
                {409, "Conflict"},
                {410, "Gone"},
                {411, "Length Required"},
                {412, "Precondition Failed"},
                {413, "Payload Too Large"},
                {414, "URI Too Long"},
                {415, "Unsupported Media Type"},
                {416, "Range Not Satisfiable"},
                {417, "Expectation Failed"},
                {418, "I'm a teapot"},
                {421, "Misdirected Request"},
                {422, "Unprocessable Entity"},
                {423, "Locked"},
                {424, "Failed Dependency"},
                {425, "Too Early"},
                {426, "Upgrade Required"},
                {428, "Precondition Required"},
                {429, "Too Many Requests"},
                {431, "Request Header Fields Too Large"},
                {451, "Unavailable For Legal Reasons"},
                {501, "Not Implemented"},
                {502, "Bad Gateway"},
                {503, "Service Unavailable"},
                {504, "Gateway Timeout"},
                {505, "HTTP Version Not Supported"},
                {506, "Variant Also Negotiates"},
                {507, "Insufficient Storage"},
                {508, "Loop Detected"},
                {510, "Not Extended"},
                {511, "Network Authentication Required"}
            };

std::unordered_map<std::string, std::string> mime_msg_ =
            {
                {".aac", "audio/aac"},
                {".abw", "application/x-abiword"},
                {".arc", "application/x-freearc"},
                {".avi", "video/x-msvideo"},
                {".azw", "application/vnd.amazon.ebook"},
                {".bin", "application/octet-stream"},
                {".bmp", "image/bmp"},
                {".bz", "application/x-bzip"},
                {".bz2", "application/x-bzip2"},
                {".csh", "application/x-csh"},
                {".css", "text/css"},
                {".csv", "text/csv"},
                {".doc", "application/msword"},
                {".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
                {".eot", "application/vnd.ms-fontobject"},
                {".epub", "application/epub+zip"},
                {".gif", "image/gif"},
                {".htm", "text/html"},
                {".html", "text/html"},
                {".ico", "image/vnd.microsoft.icon"},
                {".ics", "text/calendar"},
                {".jar", "application/java-archive"},
                {".jpeg", "image/jpeg"},
                {".jpg", "image/jpeg"},
                {".js", "text/javascript"},
                {".json", "application/json"},
                {".jsonld", "application/ld+json"},
                {".mid", "audio/midi"},
                {".midi", "audio/x-midi"},
                {".mjs", "text/javascript"},
                {".mp3", "audio/mpeg"},
                {".mpeg", "video/mpeg"},
                {".mpkg", "application/vnd.apple.installer+xml"},
                {".odp", "application/vnd.oasis.opendocument.presentation"},
                {".ods", "application/vnd.oasis.opendocument.spreadsheet"},
                {".odt", "application/vnd.oasis.opendocument.text"},
                {".oga", "audio/ogg"},
                {".ogv", "video/ogg"},
                {".ogx", "application/ogg"},
                {".otf", "font/otf"},
                {".png", "image/png"},
                {".pdf", "application/pdf"},
                {".ppt", "application/vnd.ms-powerpoint"},
                {".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
                {".rar", "application/x-rar-compressed"},
                {".rtf", "application/rtf"},
                {".sh", "application/x-sh"},
                {".svg", "image/svg+xml"},
                {".swf", "application/x-shockwave-flash"},
                {".tar", "application/x-tar"},
                {".tif", "image/tiff"},
                {".tiff", "image/tiff"},
                {".ttf", "font/ttf"},
                {".txt", "text/plain"},
                {".vsd", "application/vnd.visio"},
                {".wav", "audio/wav"},
                {".weba", "audio/webm"},
                {".webm", "video/webm"},
                {".webp", "image/webp"},
                {".woff", "font/woff"},
                {".woff2", "font/woff2"},
                {".xhtml", "application/xhtml+xml"},
                {".xls", "application/vnd.ms-excel"},
                {".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
                {".xml", "application/xml"},
                {".xul", "application/vnd.mozilla.xul+xml"},
                {".zip", "application/zip"},
                {".3gp", "video/3gpp"},
                {".3g2", "video/3gpp2"},
                {".7z", "application/x-7z-compressed"}
            };

class Util
{
public:
    // 字符串的分割功能
    static size_t Split(const std::string &src, const std::string &sep, std::vector<std::string> *ret)
    {
        // 对于字符串起始位置的偏移量，用于find中
        int offset = 0;
        int sz = src.size();
        while (offset < sz)
        {
            int pos = src.find(sep, offset);

            // 如果找不到分隔符了，那就说明剩余的字符为一个字符串
            if (pos == std::string::npos)
            {
                ret->push_back(src.substr(offset));
                break;
            }
            // 如果找到了字符但是和我们偏移量的位置相同，说明没有字符可以被截取，应该跳过
            if (offset == pos)
            {
                offset = pos + sep.size();
                continue;
            }
            // 截取字符串加入结果中
            ret->push_back(src.substr(offset, pos - offset));
            offset = pos + sep.size();
        }

        return ret->size();
    }

    // 读取文件
    static bool ReadFile(const std::string &file_name, std::string *buff)
    {
        // 创建一个读文件流,以二进制方式读取，就是按照文件原本的样子不做任何修改读取
        std::ifstream ifs(file_name, std::ios::binary);
        if (!ifs.is_open())
        {
            DBG_LOG("OPEN %S FILE FAILED!!", file_name);
            return false;
        }
        // 将文件指针移动到文件末尾
        ifs.seekg(0, ifs.end);
        // 读取文件指针到文件起始位置的偏移量
        size_t len = ifs.tellg();
        // 移动文件指针到起始位置
        ifs.seekg(0, ifs.beg);
        buff->resize(len);

        // 读取文件内容到buff
        ifs.read(&(*buff)[0], len);

        // 如果读取失败会返回false
        if (ifs.good() == false)
        {
            DBG_LOG("FILE %s READ FAILED!!", file_name);
            ifs.close();
            return false;
        }
        ifs.close();
        return true;
    }
    // 写入文件
    static bool WriteFile(const std::string &file_name, const std::string &buff)
    {
        // trunc的作用是删除文件的原有内容
        // ofstream文件不存在会自动创建文件
        std::ofstream ofs(file_name, std::ios::binary | std::ios::trunc);
        if (!ofs.is_open())
        {
            DBG_LOG("OPEN %S FILE FAILED!!", file_name);
            return false;
        }

        // 向文件中写入数据
        ofs.write(buff.c_str(), buff.size());

        if (ofs.good() == false)
        {
            DBG_LOG("FILE %s WRITE FAILED!!", file_name);
            ofs.close();
            return false;
        }
        ofs.close();
        return true;
    }

    // Url编码
    static std::string UrlEncode(const std::string &str, bool conver_space_to_add_)
    {
        std::string ret;
        for (auto c : str)
        {
            // RFC3986文档规定的非特殊字符：
            // isalnum判断字符是否为数字或字母
            if (c == '.' || c == '-' || c == '_' || c == '~' || isalnum(c))
            {
                ret += c;
            }
            // 将空格转化为+，W3C标准规定的，查询字符串需要这样转换
            else if (c == ' ' && conver_space_to_add_ == true)
            {
                ret += '+';
            }
            // RFC3986文档：按照编码格式将ascii码值转化为%HH，两个十六进制字符
            else
            {
                // 多开一位为了加一个\0,sprintf自动加
                char tmp[4] = {0};
                // 转换为%HH格式放入tmp
                // sprintf 和 printf的区别是一个是打印，一个是放在一块区间中
                sprintf(tmp, "%%%02X", c);
                ret += tmp;
            }
        }

        return ret;
    }

    static int HexToInt(char c)
    {
        if (c >= '0' && c <= '9')
        {
            return c - '0';
        }
        else if (c >= 'a' && c <= 'z')
        {
            return c - 'a' + 10;
        }
        else if (c >= 'A' && c <= 'Z')
        {
            return c - 'A' + 10;
        }

        return -1;
    }

    // Url解码
    static std::string UrlDecode(const std::string &str, bool conver_add_to_space)
    {
        std::string ret;
        int sz = str.size();
        for (int i = 0; i < sz; i++)
        {
            if (str[i] == '%' && i + 2 < sz)
            {
                int c1 = HexToInt(str[i + 1]);
                int c2 = HexToInt(str[i + 2]);
                char tmp = (c1 << 4) + c2;
                ret += tmp;
                i += 2;
            }
            else if (str[i] == '+' && conver_add_to_space == true)
            {
                ret += ' ';
            }
            else
            {
                ret += str[i];
            }
        }

        return ret;
    }
    // 根据状态获取状态描述信息
    static std::string StatuDesc(int statu)
    {
        
        auto it = statu_msg_.find(statu);
        if (it == statu_msg_.end())
        {
            return "Uknown";
        }
        return it->second;
    }
    // 通过文件后缀获取mime
    static std::string ExtMime(const std::string &file_name)
    {
        
        int pos = file_name.find_last_of('.');
        //在某些下载文件的场景中，服务端可能会返回文件流，并在返回头中带上Content-Type: application/octet-stream\
        告知浏览器这是一个字节流，浏览器处理字节流的默认方式就是下载。
        if (pos == std::string::npos)
        {
            return "application/octet-stream";
        }
        std::string ext = file_name.substr(pos);

        auto it = mime_msg_.find(ext);
        if (it == mime_msg_.end())
        {
            return "application/octet-stream";
        }
        return it->second;
    }

    // 用到了lindx接口stat来判断
    //  判断是否是目录
    static bool IsDirectory(const std::string &file_name)
    {
        struct stat st;
        int ret = stat(file_name.c_str(), &st);
        if (ret < 0)
        {
            return false;
        }
        return S_ISDIR(st.st_mode);
    }
    // 判断是否是普通文件
    static bool IsRegular(const std::string &file_name)
    {
        struct stat st;
        int ret = stat(file_name.c_str(), &st);
        if (ret < 0)
        {
            return false;
        }
        return S_ISREG(st.st_mode);
    }

    // 思想，根据深度来判断我们的路径是否合法
    // 比如"/index.html"就是在我们的资源根目录下进行资源获取
    // 在'/'后就往下一层
    //  请求资源路径是否合法
    static bool IsValidPath(const std::string &file_name)
    {
        std::vector<std::string> ret;
        Split(file_name, "/", &ret);
        int level = 0;

        for (auto &s : ret)
        {
            if (s == "..")
            {
                level--;
                if (level < 0)
                {
                    return false;
                }
            }
            else
                level++;
        }

        return true;
    }
};

class HttpRequest
{
public:
    // 请求方法
    std::string method_;
    // 资源路径
    std::string resou_path_;
    // 协议版本
    std::string version_;
    // 请求正文
    std::string body_;
    // 资源路径的正则提取数据
    std::smatch matches_;
    // 查询字符串
    std::unordered_map<std::string, std::string> params_;
    // 请求头部字段
    std::unordered_map<std::string, std::string> headers_;

public:
    HttpRequest(): version_("HTTP/1.1")
    {}
    // 重置，避免影响下一个连接
    void Reset()
    {
        method_.clear();
        resou_path_.clear();
        version_ = "HTTP/1.1";
        body_.clear();
        std::smatch matches;
        matches_.swap(matches);
        params_.clear();
        headers_.clear();
    }

    // 设置头部字段
    void SetHeader(const std::string &key, const std::string &val)
    {
        headers_.insert(make_pair(key, val));
    }
    // 查询头部字段
    bool HasHeader(const std::string &key)const
    {
        auto it = headers_.find(key);
        if (it == headers_.end())
        {
            return false;
        }
        return true;
    }
    // 获取头部字段value
    std::string GetHeader(const std::string &key) const
    {
        auto it = headers_.find(key);
        if (it == headers_.end())
        {
            return "";
        }
        return it->second;
    }

    // 设置查询字符串
    void SetParam(const std::string &key, const std::string &val)
    {
        params_.insert(make_pair(key, val));
    }
    // 查询头部字段
    bool HasParam(const std::string &key) const
    {
        auto it = params_.find(key);
        if (it == params_.end())
        {
            return false;
        }
        return true;
    }
    // 获取头部字段value
    std::string GetParam(const std::string &key) const
    {
        auto it = params_.find(key);
        if (it == params_.end())
        {
            return "";
        }
        return it->second;
    }

    // 获取正文长度
    size_t GetContentLength() const
    {
        if (HasHeader("Content-Length") == false)
        {
            return 0;
        }
        std::string cont_len = GetHeader("Content-Length");
        return std::stoul(cont_len);
    }

    // 判断是否是长连接
    bool IsLongConnection() const
    {
        if (HasHeader("Connection") == true && GetHeader("Connection") == "keep-alive")
        {
            return true;
        }

        return false;
    }
};

class HttpResponse
{
public:
    // 状态码
    int statu_;
    std::string body_;//正文部分
    std::unordered_map<std::string, std::string> headers_;//头部字段键值对
    bool redirect_flag_;//重定向标志
    std::string redirect_url_;//重定向url

public:
    HttpResponse() : statu_(), redirect_flag_(false)
    {
    }
    HttpResponse(int statu) : statu_(statu), redirect_flag_(false)
    {
    }
    // 重置，避免影响下一个连接
    void Reset()
    {
        body_.clear();
        headers_.clear();
        redirect_url_.clear();
        redirect_flag_ = false;
        statu_ = 200;
    }

    // 设置头部字段
    void SetHeader(const std::string &key, const std::string &value)
    {
        headers_.insert(make_pair(key, value));
    }
    // 查询头部字段
    bool HasHeader(const std::string &key) const
    {
        auto it = headers_.find(key);
        if (it == headers_.end())
        {
            return false;
        }
        return true;
    }
    // 获取头部字段value
    std::string GetHeader(const std::string &key) const
    {
        auto it = headers_.find(key);
        if (it == headers_.end())
        {
            return "";
        }
        return it->second;
    }
    void SetContent(const std::string &body, const std::string &type = "text/html")
    {
        body_ = body;
        SetHeader("Content-Type", type);
    }
    // 302重定向
    void SetRedirect(const std::string &url, int statu = 302)
    {
        redirect_url_ = url;
        statu_ = statu;
        redirect_flag_ = true;
    }
    // 判断是否是长连接
    bool IsLongConnection() const
    {
        if (HasHeader("Connection") == true && GetHeader("Connection") == "keep-alive")
        {
            return true;
        }

        return false;
    }
};

typedef enum
{
    HTTP_RECEIVE_ERROR,
    HTTP_RECEIVE_LINE,
    HTTP_RECEIVE_HEADER,
    HTTP_RECEIVE_BODY,
    HTTP_RECEIVE_OVER
} HttpReceStatu;

// 8k
#define MAX_LINE 8192
class HttpContext
{
private:
    // 响应状态码
    int resp_statu_;
    // 请求接收解析状态
    HttpReceStatu recv_statu_;
    // 请求解析后的信息
    HttpRequest request_;

private:
    // 解析请求行
    bool ParseHttpLine(const std::string &line)
    {
        // 存储正则匹配后的数据
        std::smatch matches;
        // 正则匹配规则,icase标志位会忽略大小写
        std::regex e("(GET|POST|PUT|HEAD|SET|DELETE) ([^?]*)(?:\\?(.*))? (HTTP/1\\.[01])(?:\r|\r\n)?",std::regex::icase);
        bool ret = std::regex_match(line, matches, e);
        if (ret == false)
        {
            // 400,  "Bad Request"
            resp_statu_ = 400;
            recv_statu_ = HTTP_RECEIVE_ERROR;
            return false;
        }

        // 请求行经过正则匹配后得到的数据：
        //  GET /wwwroot/index.html?username=wahaha&passwoed=123456 HTTP/1.1\r\n
        //  GET
        //  /wwwroot/index.html
        //  username=wahaha&passwoed=123456
        //  HTTP/1.1

        // 对请求方法的填入
        request_.method_ = matches[1];
        //前两个参数是要转换的区间，第三个为放在那里，第四个为方法
        std::transform(request_.method_.begin(), request_.method_.end(), request_.method_.begin(), ::toupper);
        // 请求资源路径
        // 因为特殊字符串在请求中已经进行了Url编码，因此我们这里需要解码，不需要将+转空格
        request_.resou_path_ = Util::UrlDecode(matches[2], false);
        // 协议版本
        request_.version_ = matches[4];
        // 用（&）对查询字符串做分割，得到每个key-value格式的键值对
        std::vector<std::string> query_string_array;
        std::string query_string = matches[3];
        Util::Split(query_string, "&", &query_string_array);
        // 再对键值对以（=）进行切割，存入我们的params_中
        for (auto &str : query_string_array)
        {
            int pos = str.find('=');
            if (pos == std::string::npos)
            {
                // 400,  "Bad Request"
                resp_statu_ = 400;
                recv_statu_ = HTTP_RECEIVE_ERROR;
                return false;
            }
            // 因为在查询字符串中，我们不仅要解码，还需要将+转换为空格字符——W3C文档规定
            std::string key = Util::UrlDecode(str.substr(0, pos), true);
            std::string val = Util::UrlDecode(str.substr(pos + 1), true);
            request_.SetParam(key, val);
        }
        return true;
    }

    // 从接受缓冲区拿取数据
    bool RecvHttpLine(Buffer *buffer)
    {
        if (recv_statu_ != HTTP_RECEIVE_LINE)
            return false;
        // 需要考虑：请求行数据不足一行或者数据太大
        std::string line = buffer->GetLineAndPop();
        if (line.size() == 0)
        {
            // 请求行的一行内容太多不处理
            if (buffer->ReadableSize() > MAX_LINE)
            {
                // 414,  "URI Too Long"
                resp_statu_ = 414;
                recv_statu_ = HTTP_RECEIVE_ERROR;
                return false;
            }
            // 如果没有拿到一行数据，就等数据够了再拿
            return true;
        }

        // 如果获取到的一行数据太大我们也不处理
        if (line.size() > MAX_LINE)
        {
            // 414,  "URI Too Long"
            resp_statu_ = 414;
            recv_statu_ = HTTP_RECEIVE_ERROR;
            return false;
        }
        // 接收成功就去解析
        bool ret = ParseHttpLine(line);
        if (ret == false)
        {
            return false;
        }
        recv_statu_ = HTTP_RECEIVE_HEADER;
        return true;
    }

    bool ParseHttpHeader(std::string &line)
    {
        //如果末尾有\r\n我们应该去掉
        if (line.back() == '\n') line.pop_back();
        if (line.back() == '\r') line.pop_back();
        // 查找分隔字符串": "
        int pos = line.find(": ");
        if (pos == std::string::npos)
        {
            // 400,  "Bad Request"
            resp_statu_ = 400;
            recv_statu_ = HTTP_RECEIVE_ERROR;
            return false;
        }
        // 因为在查询字符串中，我们不仅要解码，还需要将+转换为空格字符——W3C文档规定
        std::string key = line.substr(0, pos);
        std::string val = line.substr(pos + 2);
        request_.SetHeader(key, val);
        return true;
    }

    bool RecveHttpHeader(Buffer *buffer)
    {
        if (recv_statu_ != HTTP_RECEIVE_HEADER)
            return false;
        // 这里与请求行的接收不同点就是：他的格式为:key: val\r\nkey: val\r\n\...
        // 因此这里需要循环获取，知道获取到\r\n为止
        while (1)
        {
            // 需要考虑：请求行数据不足一行或者数据太大
            std::string line = buffer->GetLineAndPop();
            if (line.size() == 0)
            {
                // 请求行的一行内容太多不处理
                if (buffer->ReadableSize() > MAX_LINE)
                {
                    // 414,  "URI Too Long"
                    resp_statu_ = 414;
                    recv_statu_ = HTTP_RECEIVE_ERROR;
                    return false;
                }
                // 如果没有拿到一行数据，就等数据够了再拿
                return true;
            }

            // 如果获取到的一行数据太大我们也不处理
            if (line.size() > MAX_LINE)
            {
                // 414,  "URI Too Long"
                resp_statu_ = 414;
                recv_statu_ = HTTP_RECEIVE_ERROR;
                return false;
            }
            // 如果获取到"\r\n"就退出
            if (line == "\r\n")
            {
                break;
            }
            // 接收成功就去解析
            bool ret = ParseHttpHeader(line);
            if (ret == false)
            {
                return false;
            }
        }
        recv_statu_ = HTTP_RECEIVE_BODY;
        return true;
    }

    bool RecveHttpBody(Buffer *buffer)
    {
        if (recv_statu_ != HTTP_RECEIVE_BODY)
            return false;

        // 获取我们头部字段中正文长度,我们在获取头部字段中已经填写了
        size_t content_length = request_.GetContentLength();
        // 如果没有字段直接返回即可
        if (content_length == 0)
        {
            recv_statu_ = HTTP_RECEIVE_OVER;
            return true;
        }
        // 若果有,就往我们的request_.body_中存入数据即可
        // 先求出我们正文所需要的长度
        size_t rest_len = content_length - request_.body_.size(); // 这里求的是我们所需的剩余长度，可能它的正文是分了几份发来的
        // 1.如果缓冲区中的数据足够我们的正文长度
        if (buffer->ReadableSize() >= rest_len)
        {
            request_.body_.append(buffer->ReadPosition(), rest_len);
            buffer->MoveReaderOffset(rest_len);
            recv_statu_ = HTTP_RECEIVE_OVER;
            return true;
        }
        // 2.如果缓冲区不够，那么就先获取一部分，剩下的下次在获取
        request_.body_.append(buffer->ReadPosition(), buffer->ReadableSize());
        buffer->MoveReaderOffset(buffer->ReadableSize());
        return true;
    }

public:
    HttpContext() : resp_statu_(200), recv_statu_(HTTP_RECEIVE_LINE)
    {
    }
    void Reset()
    {
        resp_statu_ = 200;
        recv_statu_ = HTTP_RECEIVE_LINE;
        request_.Reset();
    }

    int GetRespStatu()
    {
        return resp_statu_;
    }
    HttpReceStatu GetRecvStatu()
    {
        return recv_statu_;
    }
    HttpRequest &GetParstRequest()
    {
        return request_;
    }
    void RecvHttpRequese(Buffer *buffer)
    {
        // 简易的状态机，不同的状态做不同的事情，不需要break是因为，我们不仅有状态保护，而且前一个事件处理完后应该接着向下处理，它是一个完整的请求。（正文可能不完整）
        switch (recv_statu_)
        {
            case HTTP_RECEIVE_LINE:
                RecvHttpLine(buffer);
            case HTTP_RECEIVE_HEADER:
                RecveHttpHeader(buffer);
            case HTTP_RECEIVE_BODY:
                RecveHttpBody(buffer);
        }
    }
};

class HttpServer
{
private:
    // GET\POST\PUT\DELETE的功能路由标，用来存放不同请求的路径对应的处理函数
    // key为一个正则表达式规则
    using Handler = std::function<void(const HttpRequest &, HttpResponse *)>;
    using Handlers = std::vector<std::pair<std::regex, Handler>>;
    Handlers get_handler_;
    Handlers post_handler_;
    Handlers put_handler_;
    Handlers delete_handler_;
    // 静态资源根目录,用来获取静态资源的
    std::string basedir_;
    // tcp服务器
    TcpServer tcpserver_;

private:
    // 连接获取消息后的处理回调函数
    // 对缓冲区的解析 + 处理
    void OnMessage(const SharedptrCon &conn, Buffer *buffer)
    {
        while (buffer->ReadableSize() > 0)
        {
            // 1.获取上下文
            HttpContext *context = conn->GetContext()->Get<HttpContext>();
            // 2.对buffer中的数据进行解析，存入context中
            context->RecvHttpRequese(buffer);
            HttpResponse rsp(context->GetRespStatu());
            // 获取解析好的resqst
            HttpRequest &request = context->GetParstRequest();
            // 如果解析失败了，那么我们的响应状态码一定>=400，这时我们需要断开连接，并且将错误响应
            if (context->GetRespStatu() >= 400)
            {
                ErrorHandler(request, &rsp);//填充错误响应
                WriteResponse(conn, request, rsp);//组织相应发送给给客户端
                context->Reset();
                buffer->MoveReaderOffset(buffer->ReadableSize());//出错了就把缓冲区数据清空,不然缓冲区一直有数据，就会一直调用onmessqge
                conn->ShutDown();//关闭连接
                return;
            }
            if (context->GetRecvStatu() != HTTP_RECEIVE_OVER) 
            {
                //当前请求还没有接收完整,则退出，等新数据到来再重新继续处理
                return;
            }
            // 3.对我们解析好的请求进行业务处理
            Route(request, &rsp);
            // 4.业务处理好后，就通过response构建一个http响应格式的协议发送回去
            WriteResponse(conn, request, rsp);
            //每次处理完需要重置下context
            context->Reset();
            // 5.业务处理好后，短链接就直接关闭
            if (rsp.IsLongConnection() == false)
            {
                conn->ShutDown();
            }
        }
    }
    // 解析数据出错时调用的函数
    void ErrorHandler(const HttpRequest &req, HttpResponse *rsp)
    {
        std::string body;
        body += "<html>";
        body += "<head>";
        body += "<meta http-equiv='Content-Type' content='text/html;charset=utf-8'>";
        body += "</head>";
        body += "<body>";
        body += "<h1>";
        body += std::to_string(rsp->statu_);
        body += " ";
        body += Util::StatuDesc(rsp->statu_);
        body += "</h1>";
        body += "</body>";
        body += "</html>";
        rsp->SetContent(body, "text/html");
    }

    // 连接建立时需要调用的函数，为其设置上下文
    void OnConnection(const SharedptrCon &conn)
    {
        //创建一个上下文
        conn->SetContext(HttpContext());
        DBG_LOG("NEW CONNECTION %p",conn.get());
    }
    // 静态资源请求的处理
    void StaticHandler(const HttpRequest &req, HttpResponse *rsp)
    {
        std::string resource_path = basedir_ + req.resou_path_;
        if (resource_path.back() == '/')
        {
            resource_path += "index.html";
        }
        //将静态资源文件数据读取出来，放入rsp中
        bool ret = Util::ReadFile(resource_path, &rsp->body_);
        if (ret == false)
        {
            return;
        }
        //获取文件的mime
        std::string mime = Util::ExtMime(resource_path);
        rsp->SetHeader("Content-Type",mime);
    }
    // 功能性资源的查询并且处理
    void Dispatcher(const HttpRequest &req, HttpResponse *rsp, const Handlers& handlers)
    {
        // 在请求方法对应的路由表中查询对应的方法，有则调用，没有就返回状态码404
        // 使用路由表中存储的正则表达式匹配资源路径，匹配成功的就执行对应的函数
        for (auto& handler : handlers)
        {
            const std::regex& e = handler.first;
            std::smatch match;
            bool ret = std::regex_match(req.resou_path_, match, e);
            if(ret == false)
            {
                continue;
            }
            //如果找到了就执行对应的函数，然后返回
            return handler.second(req,rsp);
        }
        rsp->statu_ = 404;
    }
    // 将HttpResponse整理成http协议对应的格式发送
    void WriteResponse(const SharedptrCon &conn, const HttpRequest &req, HttpResponse &rsp)
    {
        // 1.完善头部字段
        //是否支持长连接
        if (req.IsLongConnection() == true)
        {
            rsp.SetHeader("Connection","keep-alive");
        }
        else
        {
            rsp.SetHeader("Connection","close");
        }
        //是否设置正文长度
        if (rsp.body_.empty() == false && rsp.HasHeader("Content-Length") == false)
        {
            rsp.SetHeader("Content-Length",std::to_string(rsp.body_.size()));
        }
        //是否设置正文类型
        if (rsp.body_.empty() == false && rsp.HasHeader("Content-Type") == false)
        {
            rsp.SetHeader("Content-Type","application/octet-stream");
        }
        //是否重定向
        if (rsp.redirect_flag_ == true)
        {
            rsp.SetHeader("Location",rsp.redirect_url_);
        }
        // 2.组织成http协议响应格式
        std::stringstream rsp_str;
        //状态行
        rsp_str << req.version_ << " " << rsp.statu_ << " " << Util::StatuDesc(rsp.statu_) << "\r\n";
        //头部字段
        for (auto& head : rsp.headers_)
        {
            rsp_str << head.first << ": " << head.second << "\r\n";
        }
        //空行
        rsp_str << "\r\n";
        //正文
        rsp_str << rsp.body_;
        //将组织好的响应发送回去
        conn->Send(rsp_str.str().c_str(),rsp_str.str().size());
    }
    // 选择资源的类型，静态还是功能性
    void Route(HttpRequest &req, HttpResponse *rsp)
    {
        // 1.分辨是静态资源请求还是功能性请求
        // 如果是静态请求，那么就调用静态资源处理函数
        // 否则去请求路由表中查询对应的函数处理
        // 如果既不是静态资源请求，又没有路由表函数来处理，那么久设置返回状态码405,没有对应的方法
        if (IsStaticHandler(req) == true)
        {
            return StaticHandler(req,rsp);
        }
        //head的区别是他不要响应正文
        if (req.method_ == "GET" || req.method_ == "HEAD")
        {
            return Dispatcher(req, rsp, get_handler_);
        }
        else if (req.method_ == "POST")
        {
            return Dispatcher(req, rsp, post_handler_);
        }
        else if (req.method_ == "PUT")
        {
            return Dispatcher(req, rsp, put_handler_);
        }
        else if (req.method_ == "DELETE")
        {
            return Dispatcher(req, rsp, delete_handler_);
        }
        //走到这里表示没有方法与之匹配
        //Method Not Allowed
        rsp->statu_ = 405;
    }
    bool IsStaticHandler(const HttpRequest &req)
    {
        // 1.必须设置了静态资源根目录
        if (basedir_.empty())
        {
            return false;
        }
        // 2.请求方法必须是GET或者HEAD
        if (req.method_ != "GET" && req.method_ != "HEAD")
        {
            return false;
        }
        // 3.请求的资源路径必须是合法的
        if (Util::IsValidPath(req.resou_path_) == false)
        {
            return false;
        }
        // 4.处理特殊的请求资源路径，如果是一个目录，我们需要在后边追加上一个index.html
        //并且需要用一个临时对象存储我们的静态资源根目录 + 资源路径
        //如果不是静态资源请求，我们不能修改原来的路径
        std::string resource_path = basedir_ + req.resou_path_;
        if (resource_path.back() == '/')
        {
            resource_path += "index.html";
        }

        // 5.判断是否是一个普通文件，文件是否存在
        if (Util::IsRegular(resource_path) == false)
        {
            return false;
        }
        //走到这里，那么这个请求是一个静态资源请求，最后将路径写回req中
        return true;
    }

public:
    HttpServer(uint16_t port,int timeout = DEFAULT_TIMEOUT) : tcpserver_(port)
    {
        tcpserver_.EnableInactiveRelease(timeout);
        tcpserver_.SetConnectCallback(std::bind(&HttpServer::OnConnection, this, std::placeholders::_1));
        tcpserver_.SetMessagetCallback(std::bind(&HttpServer::OnMessage, this, std::placeholders::_1, std::placeholders::_2));
    }
    // 设置GET/POST/HEAD/DELETE的功能路由表,(正则表达式)-函数指针
    void Get(const std::string &regex, const Handler &handler)
    {
        get_handler_.push_back(std::make_pair(std::regex(regex),handler));
    }
    void Post(const std::string &regex, const Handler &handler)
    {
        post_handler_.push_back(std::make_pair(std::regex(regex),handler));
    }
    void Put(const std::string &regex, const Handler &handler)
    {
        put_handler_.push_back(std::make_pair(std::regex(regex),handler));
    }
    void Delete(const std::string &regex, const Handler &handler)
    {
        delete_handler_.push_back(std::make_pair(std::regex(regex),handler));
    }
    // 设置静态资源根目录
    void SetBasedir(const std::string &basedir)
    {
        assert(Util::IsDirectory(basedir) == true);
        basedir_ = basedir;
    }
    // 设置从属线程数量
    void SetThreadCount(int count)
    {
        tcpserver_.SetThreadCount(count);
    }
    // 启动服务
    void Start()
    {
        tcpserver_.Start();
    }
};
